////////////////////////////////////////////////////////////////
//
//       Filename:  ExplorerKernel.go
//
//        Version:  1.0
//        Created:  2022年11月02日 01时19分29秒
//       Revision:  none
//       Compiler:  go
//
//         Author:  alpha
//                  songbangchengjin
//   Organization:  alpha
//       Contacts:  chenxinquan@kylinos.com
//                  songbangchengjin@kylinos.com
//
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// Description:
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// Log:
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// Todo:
//
////////////////////////////////////////////////////////////////

package genmai

import (
    "os"
    "fmt"
    "time"
    "syscall"
    sandbox "main/genmai/Sandbox"
    inter "main/genmai/Interpreter"
)

type
ExplorerConfigKernel struct {
    FormatVer           int
    Id                  string
    Belong              string
    PocHazardLevel      string
    Source              string
    SiteInfo            SiteInfo
    SiteRequests        SiteRequests
}

type
ExplorerKernel struct {
    ExplorerCommon
    /* */
    //EkConfigParser  ConfigParserBase
    //EkConfig        ExplorerConfigKernel
    /* */
    EkSandbox       sandbox.SandboxBase
    /* */
    isSetup             bool
}


///////////////////////////////
// ExplorerKernel functions
func
(ek *ExplorerKernel)GetExplorerConfigKernel() (config *ExplorerConfigKernel, rc error) {
    cf, ret := ek.ExplorerCommon.EcConfig.(*ExplorerConfigKernel)
    /* */
    if (true == ret) {
        rc = nil
    } else {
        // TODO: ERR_CONVERSION_FAILED
    }

    config = cf
    /* */
    return config, rc
}

func
(ek *ExplorerKernel)SetupSandbox(sb sandbox.SandboxBase) {
    ek.EkSandbox    = sb
    /* */
    ek.isSetup      = true
}

func
(ek *ExplorerKernel)exploreWithPath(interpreter string,interArgs []string,exec string,
                                  args ...string  ) error {
    interio , rc := ek.EkSandbox.Process(interpreter,interArgs,exec, args...)
    /* */
    if (nil != rc) {
        A_DEBUG_ERROR("exploreWithPath()->Process() error! rc = ", rc)
        /* */
        return rc
    }

    config, rc1 := ek.GetExplorerConfigKernel()
    rc = rc1
    if (nil != rc) {
        A_DEBUG_ERROR("exploreWithPath()-> "+
                      "GetExplorerConfigKernel() error ! rc = ",
                      rc                                        )
        /* */
        return rc
    } // if (nil != ...

    ///////////////////////////////
    // Expire timer
    expiretime := config.SiteRequests.Implement.ExpireTime
    /* */
    f := func() {
        // 想杀死整个进程组，而不是单个进程，需要传递负整数形式
        syscall.Kill(-interio.Cmd.Process.Pid, syscall.SIGKILL)
        A_DEBUG_WARNING("ID:", config.Id,
                        "takes too long! (Expiredtime = ", expiretime, "seconds)")
    }
    /* */
    timer_ := time.AfterFunc(time.Duration(expiretime) * time.Second, f)
    /* */
    defer timer_.Stop()

    for _, itr := range config.SiteRequests.Implement.Inter {
        icmd        := itr[ : inter.INTERPRETER_CMD_LEN]
        icmd_len    := len(icmd)

        for a:=0; a < 100000; a++ {
            ;
        }
        switch (icmd) {
            case inter.INTERPRETER_CMD_SEND:
                interio.Send(itr[ icmd_len : ] + "\n")
                // TODO:remove it: just for debug
                A_DEBUG_INFO("iio:", inter.INTERPRETER_CMD_SEND, itr[ icmd_len : ])

            case inter.INTERPRETER_CMD_RECV:
                // TODO
                //out, rc_t := interio.Recv( icmd_len )
                interio.Recv( len(itr[ icmd_len :]) )
                // TODO:remove it: just for debug
                A_DEBUG_INFO("iio:", inter.INTERPRETER_CMD_RECV, itr[ icmd_len : ])

            case inter.INTERPRETER_CMD_RECVUNTIL:
                interio.RecvUntil( itr[ icmd_len : ] )
                // TODO:remove it: just for debug
                A_DEBUG_INFO("iio:", inter.INTERPRETER_CMD_RECVUNTIL, itr[ icmd_len : ])

            //case ">.":
            //    A_DEBUG_INFO(">.")
            //
            //case "<?":
            //    A_DEBUG_INFO("<?")
            //
            case inter.INTERPRETER_CMD_RECV_POC_CHECK:
                ou, _ := interio.Recv( len (itr[icmd_len : ]) )
                // TODO:remove it: just for debug
                A_DEBUG_INFO("iio:", inter.INTERPRETER_CMD_RECV_POC_CHECK, itr[ icmd_len : ])
                A_DEBUG_INFO("a ou:", ou)
                /* */
                if ( ou == itr[ icmd_len : ] ) {
                    A_DEBUG_INFO("exploreWithPath():",
                                 "\"" +
                                  inter.INTERPRETER_CMD_RECV_POC_CHECK +
                                  "\":"                                 ,
                                 config.Id+" "+"Check poc successfully!"              )
                                 kernelPass:="Kernel info "+config.Id+" "+"Check poc successfully!" 
                                 fmt.Printf("%c[%d;%d;%dm%s%c[0m\n", 0x1B, 0, 0, 32, kernelPass, 0x1B)
                    /* */
                    return RC_POC_CHECK_SUCCESSFULLY
                } else {
                    A_DEBUG_INFO("exploreWithPath():",
                                 inter.INTERPRETER_CMD_RECV_POC_CHECK,
                                 config.Id+" "+"Check poc failed!"            )
                                 kernelFailed:="Kernel info "+config.Id+" "+"Check poc failed!"
                                 fmt.Printf("%c[%d;%d;%dm%s%c[0m\n", 0x1B, 0, 0, 34, kernelFailed, 0x1B)
                    /* */
                    return RC_POC_CHECK_FAILED
                }
        } // switch (inter ...
    } // for _ , itr

    return rc
}

//func
//(ek *ExplorerKernel)Explore() (rc error) {
//}

///////////////////////////////
// override ExplorerBase functions
func
(ek *ExplorerKernel)Explore() (expvul VulnInfoCommon, rc error) {


    config, rc_t := ek.GetExplorerConfigKernel()
    rc = rc_t
    if (nil != rc) {
        A_DEBUG_ERROR("Explore()->GetExplorerConfigKernel() "+
                      "error! rc = ", rc                    )
        /* */
        return VulnInfoCommon{}, rc
    }

    ///////////////
    // starting explore


    for _, im := range config.SiteRequests.ImArray {
        rc = ek.exploreWithPath(im.Inter,im.InterArgs,ek.ExplorerCommon.EcConfigFilePrefix +
                               string(os.PathSeparator)          +
                               im.Exec                                 ,
                               im.Args...                                 )

        if rc.Error() =="Poc Check Successfully!"{
            expvul.VICId             = config.Id
            expvul.VICBelong         = config.Belong
            expvul.VICPocHazardLevel = config.PocHazardLevel
            expvul.VICSource         = config.Source
            expvul.VICSiteInfo       = config.SiteInfo
        }
    } // for _, im ...


    // ending explore
    ///////////////

    return expvul, nil
}

///////////////////////////////
// override functions

